iT邦幫忙

2024 iThome 鐵人賽

DAY 9
0
Software Development

Datomic,內建事件溯源的資料庫。系列 第 9

先從 Datalog 談起 -- part 4 (parameterized queries)

  • 分享至 

  • xImage
  •  

使用 SQL 資料庫時,我們有時候會需要用到參數化查詢,比方說,為了阻擋 SQL injection 的時候。下方是一段 Postgres 的範例:

  • 準備 SQL 語句 (prepare statement)
PREPARE get_users_by_age(int) AS
SELECT id, name FROM users WHERE age = $1;
  • 執行查詢
EXECUTE get_users_by_age(30);

Datalog 的參數化查詢

下方的這個查詢是用來查找『演員 "Sylvester Stallone" 演出的所有電影名稱』

[:find ?title
 :where
 [?p :person/name "Sylvester Stallone"]
 [?m :movie/cast ?p]
 [?m :movie/title ?title]]

那如果我們需要查詢『其它演員演出的所有電影』呢?這可以利用參數化查詢來處理。Datalog 的參數化查詢主要依賴 :in 開頭的子句 (clause) 來實現。

[:find ?title
 :in $ ?name
 :where
 [?p :person/name ?name]
 [?m :movie/cast ?p]
 [?m :movie/title ?title]]

仔細看,參數化查詢相對於原本的查詢,有兩個地方做了修改:

  • 增加新的一個子句 :in $ ?name。此處的 $ 對應著資料庫值,而 ?name 則對應著演員姓名的參數值。
  • [?p :person/name "Sylvester Stallone"] 改成 [?p :person/name ?name]

Datomic 資料庫有提供一個函數 datomic.api/q ,是專門用來處理查詢的函數,它同時也會接收參數的值。

最簡單的查詢,函數的呼叫長成 (q query db),其中,query 是查詢,db 是資料庫值。在這種時候,:in 子句其實是長成 :in $ ,由於只有一個資料庫值,所以這種情況下,整個 :in 子句也可以省略不寫。

而參數化查詢,以上頭為例,函數的呼叫會長成: (q query db "Sylvester Stallone") 。其中,query 是參數化的查詢;db 是資料庫值,會代入 $"Sylvester Stallone" 是演員姓名,會代入 ?name 參數。

參數化查詢示意圖

資料庫值與 $

『咦,對應資料庫值的 $ 真有用到嗎?』

其實,完整的資料模式 (data pattern) 有五個元素。第一個元素對應的就是資料庫值,只是說,許多時候也可以不寫、省略。

[<database> <entity-id> <attribute> <value> <transaction-id>]

換言之,剛才那個參數化的查詢,也可以將每個資料模式開頭的 $ 都寫出來,寫成

[:find ?title
 :in $ ?name
 :where
 [$ ?p :person/name ?name]
 [$ ?m :movie/cast ?p]
 [$ ?m :movie/title ?title]]

而它執行出來的結果會是一樣的。

其它資源

  1. 歡迎訂閱 PruningSuccess 電子報,主要談論軟體開發、資料處理、資料分析等議題。
  2. 歡迎加入 Clojure 社群

上一篇
先從 Datalog 談起 -- part 3 (data patterns)
下一篇
先從 Datalog 談起 -- part 5 (parameterized queries)
系列文
Datomic,內建事件溯源的資料庫。25
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言